9 Novembre 2018

La problématique

  • IoT
  • Cloud
  • Performance
  • Énergie

Récap'

Les bases

1957: Création du Perceptron par Frank Rosenblatt

  • Input: \((x_1, x_2, ..., x_n)\) un vecteur de dimension \(n\)
  • Weights: \((w_1, w_2, ..., w_n)\) un vecteur de dimension \(n\)
  • Bias: \(b\), un scalaire
  • Output:

\(y = \begin{cases} 1, & \text{if $\sum_{i=1}^n x_i.w_i + b > $ seuil} \\ 0, & {otherwise} \end{cases}\)

Entrainement

Inférence

  • \(x\) vecteur représentant une observation, \(f\) fonction d'activation
  • \(a^{(1)} = x\)
  • \(z^{(2)} = a^{(1)}.W^{(1)} + b^{(1)} = x.W^{(1)} + b^{(1)}\)
  • \(a^{(2)} = f(z^{(2)})\)
  • \(z^{(3)} = a^{(2)}.W^{(2)} + b^{(2)}\)
  • \(y = a^{(3)} = f(z^{(3)})\)

GPU

Edge Computing

L'edge computing est une méthode d'optimisation employée dans le cloud computing qui consiste à traiter les données à la périphérie du réseau, près de la source des données – Wikipedia

VPU

  • dédié
  • moins de fonctionnalités
  • moins énergivore

Google AIY

Dans le Neural Compute Stick

1W vs. 180W

Démarche

  • train ton modèle
  • profile/tune/compile ton modèle sur PC
  • prototype sur système embarqué

Exemple

Alphashifumi

V2

V2

V800

L'IA dans Alphashifumi

PAPER

PAPER

Entrainement du modèle

Chargement des librairies

library(keras)
library(tensorflow)

Modèle simple

model <- keras_model_sequential()
model %>%
    layer_flatten(input_shape = c(128, 128, 1)) %>%
    layer_dense(units = 1024, activation = 'relu') %>%
    layer_dense(units = 1024, activation = 'relu') %>%
    layer_dense(units = 5, activation = 'softmax', name = 'output')
## ___________________________________________________________________________
## Layer (type)                     Output Shape                  Param #     
## ===========================================================================
## flatten_1 (Flatten)              (None, 16384)                 0           
## ___________________________________________________________________________
## dense_1 (Dense)                  (None, 1024)                  16778240    
## ___________________________________________________________________________
## dense_2 (Dense)                  (None, 1024)                  1049600     
## ___________________________________________________________________________
## output (Dense)                   (None, 5)                     5125        
## ===========================================================================
## Total params: 17,832,965
## Trainable params: 17,832,965
## Non-trainable params: 0
## ___________________________________________________________________________

Compilation

On compile le modèle :

model %>% compile(optimizer = 'rmsprop',
                  loss = 'categorical_crossentropy',
                  metrics = c('accuracy'))

Entrainement

history <- model %>% fit_generator(train_generator,
                                   validation_data = validation_generator,
                                   steps_per_epoch = nb_train_samples / batch_size,
                                   validation_steps = nb_validation_samples / batch_size,
                                   epochs = 10)
Exemple shifumi

Exemple shifumi

predict(model, sample_img)
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    0    1    0    0    0

Performance

plot(history)

Freeze du modèle

source('freeze.R')

io_names <- freeze(model)
## Model written in ./target/models/
  • le freeze permet de préparer le modèle pour l'inférence
  • suppression des couches d'entrainement
  • transformation des variables en constantes
  • modifier la précision (par ex.: float sur 32bit vers 16bit)

Toolkit

  • mvNCCheck
  • mvNCProfile
  • mvNCCompile

Compilation

On compile le modèle dans un format pris en charge par le NCS. Avec :

  • flatten_1_input_1 en entrée
  • output_1/Softmax en sortie.
mvNCCompile target/models/keras_to_tf.pb -o target/ncs/ncs.graph \
           -in $INPUT_NAME \
           -on $OUTPUT_NAME

#$

Profiling

mvNCProfile target/models/keras_to_tf.pb \
           -in $INPUT_NAME \
           -on $OUTPUT_NAME

#$

Example de rapport

Utilisation du SDK

Liste des devices

from mvnc import mvncapi
device_list = mvncapi.enumerate_devices()
print(device_list)
## [c_void_p(204899472)]
has_device = bool(device_list)

Initialisation et ouverture d'un device :

device = mvncapi.Device(device_list[0])
device.open()

Affichage de quelques options :

print(device.get_option(mvncapi.DeviceOption.RO_DEVICE_NAME))
## 2-ma2450
print(device.get_option(mvncapi.DeviceOption.RO_MEMORY_SIZE))
## 522059056
print(device.get_option(mvncapi.DeviceOption.RO_DEVICE_STATE))
## 1

Chargement du graphe

GRAPH_FILEPATH = './target/ncs/ncs.graph'
with open(GRAPH_FILEPATH, mode='rb') as f:
    graph_buffer = f.read()

On utilise la classe Graph :

graph = mvncapi.Graph('graph1')

Les entrées/sorties du graphe sont gérés par des files. On peut les créer avec les paramètres par défaut :

input_fifo, output_fifo = graph.allocate_with_fifos(device, graph_buffer)

Inférons 1/2

On charge une image :

Exemple shifumi

Exemple shifumi

from scipy import misc
import numpy
tensor = misc.imread('data/alphashifumi/test/paper/26475c05-9d1e-11e7-abeb-b1233b68540d-1.jpg')
tensor = tensor.astype(numpy.float32)

L'image est ensuite poussée dans la file d'entrée :

graph.queue_inference_with_fifo_elem(input_fifo, output_fifo, tensor, 'test paper')

Inférons 2/2

L'image va être lue par le device qui va ensuite procéder à l'inférence. Le résultat est ensuite poussé dans la file de sortie :

output, user_obj = output_fifo.read_elem()
## /usr/lib/python3.5/site-packages/mvnc/mvncapi.py:416: DeprecationWarning: The binary mode of fromstring is deprecated, as it behaves surprisingly on unicode inputs. Use frombuffer instead
##   tensor = numpy.fromstring(tensor.raw, dtype=numpy.float32)
print(output)
## [0. 1. 0. 0. 0.]
print(user_obj)
## test paper

Nettoyage

input_fifo.destroy()
output_fifo.destroy()
graph.destroy()
device.close()
device.destroy()

Benchmark

CPU vs. VPU

CPU :

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.018   0.019   0.019   0.019   0.019   0.022

VPU :

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0173  0.0183  0.0187  0.0185  0.0189  0.0192

VPU sur RPI :

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0183  0.0194  0.0194  0.0193  0.0194  0.0249

Transfer Learning

Inception

base_model <- application_inception_v3(weight = 'imagenet',
                                       include_top = FALSE,
                                       input_shape = c(img_width, img_height, 3),
                                       pooling = 'avg')

On ajoute nos couches denses :

predictions <- base_model$output %>%
    layer_dense(units = 1024, activation = 'relu') %>%
    layer_dense(units = 1024, activation = 'relu') %>%
    layer_dense(units = 512, activation = 'relu') %>%
    layer_dense(units = 5, activation = 'softmax', name = 'output')

On regroupe les morceaux

Le nouveau modèle à entrainer devient :

model <- keras_model(inputs = base_model$input, outputs = predictions)

On freeze toutes les couches, pas besoin de les réentrainer :

freeze_weights(base_model)

Tout n'est pas perdu

  • Évolution du SDK
  • NCAppZoo
  • Communauté Movidius

Conclusion

  • Neural Compute Stick
  • Inférence de réseaux
  • Prototypage
  • Performant et peu énergivore
  • SDK et API en évolution

Merci

Liens

Credits